package cloud.keveri.gateway.plugin.api.support;

import cloud.keveri.base.ErrorCode;
import cloud.keveri.base.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.lang.NonNull;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * <p>
 * 作者：沈自在
 **/
@Slf4j
public final class WebFluxResultUtils {

    private WebFluxResultUtils() {
    }

    private static Object format(ServerWebExchange exchange, Object origin) {
        // basic data or upstream data
        if (ObjectTypeUtils.isBasicType(origin) || (origin instanceof byte[])) {
            return origin;
        }
        // error error or rpc origin error.
        return JsonUtils.toJson(origin);
    }

    /**
     * TODO 暂时只处理 JSON
     */
    private static MediaType contentType(ServerWebExchange exchange, Object formatted) {
        return MediaType.APPLICATION_JSON;
    }

    /**
     *
     */
    public static Mono<Void> error(final ServerWebExchange exchange, final ErrorCode obj) {
        if (Objects.isNull(obj)) {
            return Mono.empty();
        }
        final Result<?> result = new Result<>(obj.getCode(), obj.getMessage());
        return processResult(exchange, result);
    }

    public static Mono<Void> success(final ServerWebExchange exchange, final Object obj) {
        if (Objects.isNull(obj)) {
            return Mono.empty();
        }
        final Result<?> result = Result.ok(obj);
        return processResult(exchange, result);
    }

    @NonNull
    private static Mono<Void> processResult(ServerWebExchange exchange, Result<?> result) {
        Object resultData = format(exchange, result);
        MediaType mediaType = MediaType.TEXT_PLAIN;
        if (!ObjectTypeUtils.isBasicType(result)) {
            mediaType = contentType(exchange, resultData);
        }
        exchange.getResponse().getHeaders().setContentType(mediaType);
        assert null != resultData;

        final byte[] bytes = (resultData instanceof byte[])
                ? (byte[]) resultData : resultData.toString().getBytes(StandardCharsets.UTF_8);
        return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                        .bufferFactory().wrap(bytes))
                .doOnNext(data -> exchange.getResponse().getHeaders().setContentLength(data.readableByteCount())));
    }
}
